In [4]:
import time
def timer(function):
def wrapper(*args, **kwargs):
start_time = time.time()
result = function(*args, **kwargs)
end_time = time.time()
print("{time}s".format(time=end_time-start_time))
return wrapper
# 새로운 함수를 만들고, 그 함수를 return 하는 함수 => decorator 함수
# 새롭게 만들어진 wrapper라는 함수가 사실은 실행이 된다.
In [5]:
@timer
def print_hello():
print("hello world")
In [6]:
print_hello()
#print_hello 라는 이름을 가지고 있기는 하지만, 사실상의 timer->wrapper function이 실행
In [7]:
def print_goodbye():
print("hello world_2")
wrapper = timer(print_goodbye)
In [8]:
wrapper()
#위에거랑 완전히 동일한 형태이다.
# 사실상 decorator 는 기존의 정의된 함수를 한번 묶는 것과 100% 동일하다.
In [10]:
# args, kwargs
def hello_items(**kwargs):
# 함수를 정의하는 시점에 사용하는 kwargs ( **kwargs ) => packing
# 즉, 여러 개로 들어온 값을 kwargs라는 dict로 하나로 묶은 것이다. 그래서 packing
for key, value in kwargs.items():
print("{key} => {value}".format(key=key, value=value))
In [11]:
hello_items(name="kkp", age=29)
In [12]:
information = {"name": "poy", "age": 28}
hello_items(information)
In [13]:
information = {"name": "poy", "age": 28}
hello_items(**information) # dict => key, value => unpacking
# 함수를 호출하는 시점에서 사용하는 kwargs ( **kwargs )
In [14]:
@timer
def print_student_info(name, course, age):
pass
In [15]:
print_student_info("kimkipyo", "dss", 29) # => *args => packing
# *args => ("kimkipyo", "dss", 29 ) (type은 tuple)
In [16]:
import time
# print_student_info(name, course, age)
# args = ("dobestan", "wps", 24) # packing
# print_student_info(*args) # unpacking
# 똑같이 생겼는데,
# 1. 함수 정의할 때랑 ( packing ),
# 2. 함수 호출할 때 ( unpacking )랑 반대의 기능이 기능
def timer(function):
def wrapper(*args, **kwargs): # packing => 함수 정의부
print("args => {my_args}".format(my_args=args))
print("kwargs => {my_kwargs}".format(my_kwargs=kwargs))
start_time = time.time()
result = function(*args, **kwargs) # unpacking => tuple => 하나하나 / dict => key,value...
# 함수 호출부
end_time = time.time()
print("{time}s".format(time=end_time-start_time))
return result
return wrapper
In [17]:
def hello():
print("hello world")
In [18]:
hello()
In [19]:
def execute_three_times(function):
for i in range(3):
function()
In [20]:
execute_three_times(hello())
In [21]:
execute_three_times(hello)
# 함수를 인자로 받는 것과 함수 결과값을 인자로 받는 것은 다르다.
In [22]:
def double(x):
return x * 2
def triple(x):
return x * 3
In [23]:
temp = double(4)
triple(temp) #마찬가지로 결과값이 들어가야 한다.
Out[23]:
In [24]:
# bold => <b>...</b>
# italic => <i>...</i>
# decorator 구현하기 2개
# 함수 아무거나 2개 구현하셔서
In [34]:
def bold(function):
def wrapper(*args, **kwargs):
return "<b>" + function(*args, **kwargs) + "</b>"
return wrapper
def italic(function):
def wrapper(*args, **kwargs):
return "<i>" + function(*args, **kwargs) + "</i>"
return wrapper
@bold
@italic
def return_hello():
return "hello world"
def return_goodbye():
return "good bye"
In [35]:
return_goodbye = bold(italic(return_goodbye)) # decorator 의 실제 기능 ( @... )
return_goodbye()
Out[35]:
In [36]:
return_hello()
Out[36]:
In [38]:
@italic
@bold
def return_goodbye():
return "good bye"
return_goodbye()
Out[38]:
In [39]:
#함수 안에 함수를 만드는 사례
def return_double_function():
def double(x):
return x * 2
return double
In [40]:
return_double_function()
Out[40]:
In [41]:
return_double_function()(10)
Out[41]:
In [42]:
def return_multiply_function(n):
def multiply(x):
return x * n
return multiply
In [43]:
return_multiply_function(10)(20)
Out[43]:
In [44]:
double = return_multiply_function(2)
triple = return_multiply_function(3)
quadruple = return_multiply_function(4)
In [45]:
double(2)
Out[45]:
In [46]:
triple(4)
Out[46]:
In [47]:
quadruple(10)
Out[47]:
In [48]:
ten_times = return_multiply_function(10) # 10을 곱해주는 함수
ten_times(200)
Out[48]:
In [49]:
class Timer():
def __init__(self, function):
self.function = function
In [50]:
@Timer
def print_hello():
print("hello world")
#함수와 클래스 구현이 100% 동일한 예제이다.
#print_hello = Timer(print_hello) # 이것과 위의 과정과 동일한 표현이다.
# print_hello의 type은 Timer class로부터 만들어진 => Timer object 이다.
In [52]:
print_hello() #오류의 이유는 timer 객체에다가 함수를 부르듯이 불렀기 때문에
In [53]:
class Student():
def __init__(self, name):
self.name = name
In [54]:
student = Student("kkp")
In [56]:
student() #마찬가지 이류로 오류가 난다.
In [57]:
class HelloWorld():
def __init__(self):
print("init")
def __call__(self): # 객체가 함수처럼 호출되면, `self()` 될 때, 실행된다.
print("hello world")
In [58]:
HelloWorld()
Out[58]:
In [59]:
helloworld = HelloWorld()
In [60]:
helloworld() #__call__ 함수 없었으면 오류가 난다.
In [62]:
dir(helloworld) #메쏘드와 속성들을 볼 수 있다.
Out[62]:
In [63]:
# Memoization, 기존의 결과값을 어딘가에 저장을 해서
# Factorial ( n! = n * n-1 * ... * 2 * 1 ) 을 함수로 구현
cache = {}
def factorial(n):
if n <= 1:
result = cache[n] = 1
return result
if n in cache:
return cache[n]
result = n * factorial(n-1)
cache[n] = result
return result
In [66]:
factorial(8)
Out[66]:
In [67]:
cache
Out[67]:
In [72]:
class Factorial():
def __init__(self): # 클래스 객체가 초기화될 때 실행되는 메쏘드
self.cache = {} # factorial 에 대한 연산 결과를 저장하고 있는 dict
def __call__(self, n): # 클래스 객체가 함수처럼 불릴 때 실행되는 메쏘드 ( `self(n)`, callable )
if n <= 1:
result = self.cache[n] = 1
return result
if n in self.cache:
return self.cache[n]
result = n * self.__call__(n-1) # 결과를 계산하고, 그 결과를 result
self.cache[n] = result # self.cache => {1..., n: result}
return result
def __str__(self): # 클래스 객체를 print 할 때 실행되는 메쏘드 ( `print(self)` )
return "\n".join([
"{key}! == {value}".format(key=key, value=value)
for key, value
in self.cache.items()
])
# Class Decorator => 구현할 수 있겠구나
In [73]:
factorial = Factorial() #factorial이라는 클래스에 Factorial()이라는 객체를 만듦
In [74]:
factorial(5)
Out[74]:
In [75]:
factorial.cache
Out[75]:
In [76]:
print(factorial)
In [77]:
"강아지" in ["강아지", "고양이", "이구아나"]
Out[77]:
In [78]:
"강아지" in {"강아지": "dog", "고양이": "cat"}
Out[78]:
In [80]:
"dog" in {"강아지": "dog", "고양이": "cat"}.values()
Out[80]:
In [81]:
{"강아지": "dog", "고양이": "cat"}.keys()
Out[81]:
In [82]:
{"강아지": "dog", "고양이": "cat"}.values()
Out[82]:
In [83]:
{"강아지": "dog", "고양이": "cat"}.items()
Out[83]:
In [84]:
cache = {}
In [85]:
cache[1] = 1
In [86]:
cache
Out[86]:
In [87]:
cache[2] = 2
In [89]:
cache
Out[89]:
In [90]:
cache[0] = 10
In [91]:
cache
Out[91]:
In [92]:
class Timer():
def __init__(self, function):
self.function = function
In [94]:
@Timer
def print_hello():
print("hello world")
# print_hello == Timer(print_hello)
# print_hello() == Timer(print_hello)() # Class => callable => __call__(self...)
In [95]:
print_hello() #오류가 나기 때문에 __call__ 불러야지
In [96]:
class Timer():
def __init__(self, function):
self.function = function
def __call__(self):
result = self.function()
return result
In [98]:
@Timer
def print_hello():
print("hello world")
In [99]:
print_hello()
In [109]:
import time
class Timer():
def __init__(self, function):
self.function = function
def __call__(self):
# __call__ => function decorator 에서의 wrapper 와 동일한 역할
start_time = time.time()
result = self.function()
end_time = time.time()
print("{time}s".format(time=end_time-start_time))
return result
In [110]:
@Timer
def print_hello():
print("hello world")
In [111]:
print_hello()
In [112]:
@Timer
def print_hello(name):
print("hello, " + name)
In [113]:
print_hello("kkp") #오류가 난다. 그래서 args, kwarg를 넣어줘야 한다.
In [114]:
import time
class Timer():
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
start_time = time.time()
result = self.function(*args, **kwargs)
end_time = time.time()
print("{time}s".format(time=end_time-start_time))
return result
In [115]:
@Timer
def print_hello(name):
print("hello, " + name)
In [116]:
print_hello("kkp")
In [117]:
import time
class Timer():
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
print(args)
print(kwargs)
start_time = time.time()
result = self.function(*args, **kwargs)
end_time = time.time()
print("{time}s".format(time=end_time-start_time))
return result
In [118]:
def print_name_and_age(**kwargs):
for key, value in kwargs.items():
print("{key} => {value}".format(key=key, value=value))
#일반적인 방법
In [119]:
print_name_and_age(name="kkp", age=29)
In [120]:
def print_name_and_age(**kwargs):
if kwargs.get("name"): #kwargs에 name이 있었으면
print("name => {name}".format(name=kwargs.get("name")))
if kwargs.get("age"): #kwargs에 age가 있었으면
print("나이도 입력받았습니다.")
In [121]:
print_name_and_age(name="kkp")
In [122]:
print_name_and_age(age=29)
In [123]:
print_name_and_age(name="kkp", age=29)
In [ ]:
In [124]:
class Tagify():
#<b><i>...</i></b>
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
boldify = "<b>" + self.function(*args, **kwargs) + "</b>"
italicfy = "<i>" + boldify + "</i>"
return italicfy
In [125]:
@Tagify
def print_hello():
return "hello world"
print_hello()
Out[125]:
In [126]:
class Tagify():
# <p><b><i>...</i></b></p>
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
paragraphify = self.tagify("p", self.function(*args, **kwargs))
boldify = self.tagify("b", paragraphify)
italicfy = self.tagify("i", boldify)
return italicfy
def tagify(self, tag, text):
return "<{tag}>{text}</{tag}>".format(
tag=tag,
text=text,
)
In [127]:
@Tagify
def print_hello():
return "hello world"
print_hello()
Out[127]: